home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 18 / CU Amiga Magazine's Super CD-ROM 18 (1997)(EMAP Images)(GB)[!][issue 1998-01].iso / CUCD / Graphics / WhirlGIF / src.202_sasc / whirlgif.c < prev    next >
C/C++ Source or Header  |  1997-09-30  |  18KB  |  831 lines

  1.   
  2. /*
  3.  * whirlgif.c
  4.  *
  5.  * Copyright (C) 1995,1996 by Kevin Kadow (kadokev@msg.net)
  6.  * 
  7.  * Based on txtmerge.c
  8.  * Copyright (C) 1990,1991,1992,1993 by Mark Podlipec. 
  9.  * All rights reserved.
  10.  *
  11.  * This software may be freely copied, modified and redistributed
  12.  * without fee provided that this copyright notice is preserved 
  13.  * intact on all copies and modified copies.
  14.  * 
  15.  * There is no warranty or other guarantee of fitness of this software.
  16.  * It is provided solely "as is". The author(s) disclaim(s) all
  17.  * responsibility and liability with respect to this software's usage
  18.  * or its effect upon hardware or computer systems.
  19.  *
  20.  */
  21.  /*
  22.   * Description:
  23.   *
  24.   * This program reads in a sequence of single-image GIF format files and
  25.   * outputs a single multi-image GIF file, suitable for use as an animation.
  26.   *
  27.   * TODO:
  28.   *
  29.   * More options for dealing with the colormap
  30.   *
  31.   * Eventually, I'd like to have this program compare the current image
  32.   * with the previous image and check to see if only a small section of
  33.   * the screen changed from the previous image. Worth a shot.
  34.   */
  35.  
  36.  /*
  37.   * Rev 2.02    07Jul97 Hannu Nevalainen
  38.   *     -disp was always "none"
  39.   * Rev 2.01    31Aug96 Kevin Kadow
  40.   *    disposal
  41.   * Rev 2.00    05Feb96 Kevin Kadow
  42.   *    transparency, gif comments,
  43.   * Rev 1.10    29Jan96 Kevin Kadow
  44.   *    first release of whirlgif
  45.   *
  46.   * txtmerge:
  47.   * Rev 1.00    23Jul91    Mark Podlipec
  48.   *    creation
  49.   * Rev 1.01    08Jan92    Mark Podlipec
  50.   *     use all colormaps, not just 1st.
  51.   *
  52.   * 
  53.   */
  54. #define DA_REV 2.02
  55.  
  56. #include <stdio.h>
  57. #include <stdlib.h>
  58. #ifdef _USE_STRINGS_H
  59. #include <strings.h>
  60. #else
  61. #include <string.h>
  62. #endif
  63.  
  64. #include "whirlgif.h"
  65.  
  66. #define MAXVAL  4100            /* maxval of lzw coding size */
  67. #define MAXVALP 4200
  68.  
  69.  
  70. static const char ver[]="$VER: WhirlGIF 2.02 (31.08.96) © 1996 by Kevin Kadow, © 1991-1992 by Mark Podlipec (Amiga Version by Michele Puccini)\0";
  71.  
  72.  
  73. /*
  74.  * Set some defaults, these can be changed on the command line
  75.  */
  76. unsigned int loop=DEFAULT_LOOP,loopcount=0,
  77.     use_colormap=DEFAULT_USE_COLORMAP,
  78.     debug_flag=0,
  79.     verbose=0;
  80.  
  81. int imagex = 0;
  82. int imagey = 0;
  83. int imagec = 0;
  84.  
  85. /* global settings for offset, transparency */
  86. Global global;
  87.  
  88. GIF_Color gif_cmap[256];
  89.  
  90. ULONG GIF_Get_Code();
  91. void GIF_Decompress();
  92. void GIF_Get_Next_Entry();
  93. void GIF_Add_To_Table();
  94. void GIF_Send_Data();
  95. void GIF_Clear_Table();
  96. void GIF_Screen_Header();
  97. void GIF_Image_Header();
  98. void GIF_Read_File();
  99. void GIF_Comment();
  100. void GIF_Loop();
  101. void GIF_GCL();
  102. void Calc_Trans();
  103. void set_offset();
  104.  
  105. GIF_Screen_Hdr gifscrn;
  106. GIF_Image_Hdr gifimage;
  107. GIF_Table table[MAXVALP];
  108.  
  109. ULONG root_code_size,code_size,CLEAR,EOI,INCSIZE;
  110. ULONG nextab;
  111. ULONG gif_mask[16] = {1,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,0,0};
  112. ULONG gif_ptwo[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,0,0};
  113.  
  114.  
  115. UBYTE gif_buff[MAXVALP];
  116. ULONG gif_block_size;
  117. int num_bits,bits;
  118.  
  119. int pic_i;
  120. char gif_file_name[BIGSTRING];
  121. int screen_was_last;
  122.  
  123.  
  124. void TheEnd()
  125. {
  126.  exit(0);
  127. }
  128.  
  129. void TheEnd1(p)
  130. char *p;
  131. {
  132.  fprintf(stderr,"%s",p);
  133.  TheEnd();
  134. }
  135.  
  136. Usage()
  137. {
  138.   fprintf(stderr,"\nUsage: whirlgif [-v] [-off x,y] [-o outfile] [-loop [count]] [-time #delay]\n");
  139.   fprintf(stderr,"\t[-debug] [-disp none | not | back | prev ] [-u 0 | 1 | false | true ]\n");
  140.   fprintf(stderr,"\t[ -i listfile] [ -trans index] file1 file2 ...\n");
  141.   exit(0);
  142. }
  143.  
  144. main(argc,argv)
  145. int argc;
  146. char *argv[];
  147. {
  148.  FILE * infile, *fout;
  149.  char temp[BIGSTRING];
  150.  int ret,i;
  151.  int count=0;
  152.  
  153.  fprintf(stderr,"whirlgif Rev 2.2  (C) 1996 by Kevin Kadow\n",DA_REV);
  154.  fprintf(stderr,"                  (C) 1991,1992 by Mark Podlipec\n");
  155.  
  156.  if (argc < 2) Usage();
  157.  
  158.  /* set global values */
  159.  screen_was_last = FALSE;
  160.  global.trans.type=TRANS_NONE;
  161.  global.trans.valid=FALSE;
  162.  global.time=DEFAULT_TIME;
  163.  global.left=0;
  164.  global.top=0;
  165.  global.disposal=DEFAULT_DISPOSAL;
  166.  
  167.  
  168.  fout=stdout;
  169.  i = 1;
  170.  while( i < argc)
  171.  {
  172.   char *p;
  173.   p = argv[i];
  174.   /*fprintf(stderr,"Option: %s\n",p);*/
  175.   if ( (p[0] == '-') || (p[0] == '+') )
  176.   { 
  177.    ++p; /* strip off the - */
  178.    switch(p[0])
  179.    {
  180.     case 'v':    /* Give lots of information */
  181.             verbose++;
  182.             i++;
  183.         fprintf(stderr,"Verbose output\n");
  184.         break;
  185.  
  186.     case 'd':    /* either Debug mode or disposal setting */
  187.         i++;
  188.         if(!strncmp("disp",p,4)) {
  189.             p=argv[i];
  190.             if(!strcmp("none",p)) 
  191.                global.disposal = DISP_NONE;
  192.             else if(!strcmp("not",p)) 
  193.                global.disposal = DISP_NOT;
  194.             else if(!strcmp("back",p)) 
  195.                global.disposal = DISP_BACK;
  196.             else if(!strcmp("prev",p)) 
  197.                global.disposal = DISP_PREV;
  198.             else global.disposal = DISP_NONE;
  199.               if(verbose) fprintf(stderr,"Disposal method set to %d (%s)\n",global.disposal,p);
  200.         }
  201.         else {
  202.             debug_flag++;
  203.             fprintf(stderr,"DEBUG: Debug Level %d\n",debug_flag);
  204.         }
  205.         i++;
  206.         break;
  207.  
  208.     case 'l':    /* Enable looping */
  209.         loop=TRUE;
  210.         i++;
  211.         if(*argv[i] !='-') {
  212.           /* a loop count was given */
  213.           loopcount=atoi(argv[i++]);
  214.           if(verbose) fprintf(stderr,"Loop %d times\n",loopcount);
  215.           }
  216.         else {
  217.           /* default to infinite loop */
  218.           loopcount=0;
  219.           if(verbose) fputs("Looping enabled\n",stderr);
  220.           }
  221.         break;
  222.  
  223.     case 'u':    /* Use colormap? true or false */
  224.         i++;
  225.         if(atoi(argv[i]) || !strcmp("true",argv[i])) use_colormap=1;
  226.         else use_colormap=0;
  227.         i++;
  228.         break;
  229.  
  230.     case 't':    /* either time or transparent */
  231.         i++;
  232.         if(!strcmp("time",p)) {
  233.             /* Delay time in 1/100's of a second */
  234.             global.time=atoi(argv[i++]);
  235.               if(verbose) fprintf(stderr,"Time (re)set to %d\n",global.time);
  236.             }
  237.         else if(!strncmp("trans",p,4)) Calc_Trans(argv[i++]);
  238.         break;
  239.  
  240.     case 'o':    /* Output file - send output to a given filename */
  241.         i++;
  242.         if(!strncmp("off",p,3)) set_offset(argv[i]);
  243.         else
  244.         /* It must be 'output, so do that */
  245.         if(NULL==(fout=fopen(argv[i],"w")))
  246.             {
  247.             fprintf(stderr,"Cannot open %s for output\n",argv[i]);
  248.             exit(1);
  249.             }
  250.         i++;
  251.         break;
  252.     case 'i':    /* input file - file with a list of images */
  253.         i++;
  254.         if(NULL != (infile=fopen(argv[i],"r"))) {
  255.             while(fgets(gif_file_name,BIGSTRING,infile)) {
  256.                 strtok(gif_file_name,"\n");
  257.                   if(!count) GIF_Read_File(fout,gif_file_name,1);
  258.                   else       GIF_Read_File(fout,gif_file_name,0);
  259.                   count++;
  260.                 }
  261.             fclose(infile);
  262.             }
  263.         else fprintf(stderr,"Cannot read list file %s\n",argv[i]);
  264.         i++;
  265.         break;
  266.     default: 
  267.         Usage();
  268.         exit(0);
  269.         break;
  270.    }
  271.    continue;
  272.   }
  273.   /* Not an option, must be the name of an input file */
  274.   if(!count) GIF_Read_File(fout,argv[i],1);
  275.   else       GIF_Read_File(fout,argv[i],0);
  276.   count++;
  277.   i++;
  278.  }
  279.  /* We're done with all the options, finish up */
  280.  if(count >0)
  281.   {
  282.   fputc(';',fout); /* image separator */
  283.   sprintf(temp,"whirlgif %2.2f (C) kadokev@msg.net. %d images",DA_REV,count);
  284.   GIF_Comment(fout,temp);
  285.   }
  286.  
  287.  fclose(fout);
  288.  fprintf(stderr,"Processed %d files.\n",count);
  289.  exit(0);
  290. }
  291.  
  292.  
  293. /*
  294.  * Read a GIF file, outputting to fname as we go.
  295.  * It would be faster to read and write the individual blocks,
  296.  * but eventually we'd like to optimize based on changes from
  297.  * previous images(ie only a small section of the image changed.
  298.  */
  299. void
  300. GIF_Read_File(fout,fname,first_image)
  301. FILE * fout;
  302. char *fname;
  303. int first_image;
  304. {
  305.  FILE *fp;
  306.  int ret,i,exit_flag;
  307.  
  308.  if ( (fp=fopen(fname,"r"))==0)
  309.  { 
  310.   fprintf(stderr,"Can't open %s for reading.\n",fname); 
  311.   TheEnd();
  312.  }
  313.  
  314.  GIF_Screen_Header(fp,fout,first_image);
  315.  
  316.  /*** read until  ,  separator */
  317.  do
  318.  {
  319.   i=fgetc(fp);
  320.   if ( (i<0) && feof(fp))
  321.   {
  322.    fclose(fp);
  323.    TheEnd1("GIF_Read_Header: Unexpected End of File\n");
  324.   }
  325.  } while(i != ',');
  326.  
  327.  if(first_image)
  328.   {
  329.    /* stuff we only do once */
  330.    if(loop) GIF_Loop(fout,loopcount);
  331.    }
  332.  if(global.time||(global.trans.type!=TRANS_NONE && global.trans.valid))
  333.     GIF_GCL(fout,global.time);
  334.  
  335.  fputc(',',fout); /* image separator */
  336.  
  337.  GIF_Image_Header(fp,fout,first_image);
  338.  
  339.  /*FOO*/
  340.  
  341.  /*** Setup ACTION for IMAGE */
  342.  
  343.  GIF_Decompress(fp,fout);
  344.  fputc(0,fout);  /* block count of zero */
  345.  
  346.  fclose(fp);
  347. }
  348.  
  349. void GIF_Decompress(fp,fout)
  350. FILE *fp,*fout;
  351. {
  352.  register ULONG code,old;
  353.  
  354.  pic_i = 0;
  355.  bits=0;
  356.  num_bits=0;
  357.  gif_block_size=0;
  358.     /* starting code size of LZW */
  359.  root_code_size=(fgetc(fp) & 0xff); fputc(root_code_size,fout);
  360.  GIF_Clear_Table();                /* clear decoding symbol table */
  361.  
  362.  code=GIF_Get_Code(fp,fout);
  363.  
  364.  if (code==CLEAR) 
  365.  {
  366.   GIF_Clear_Table(); 
  367.   code=GIF_Get_Code(fp,fout);
  368.  }
  369.  /* write code(or what it currently stands for) to file */
  370.  GIF_Send_Data(code);   
  371.  old=code;
  372.  code=GIF_Get_Code(fp,fout);
  373.  do
  374.  {
  375.   if (table[code].valid==1)    /* if known code */
  376.   {
  377.        /* send it's associated string to file */
  378.     GIF_Send_Data(code);
  379.     GIF_Get_Next_Entry(fp);       /* get next table entry (nextab) */
  380.     GIF_Add_To_Table(old,code,nextab);  /* add old+code to table */
  381.     old=code;
  382.   }
  383.   else      /* code doesn't exist */
  384.   {
  385.     GIF_Add_To_Table(old,old,code);   /* add old+old to table */
  386.     GIF_Send_Data(code);
  387.     old=code;
  388.   }
  389.   code=GIF_Get_Code(fp,fout);
  390.   if (code==CLEAR)
  391.   { 
  392.    GIF_Clear_Table();
  393.    code=GIF_Get_Code(fp,fout);
  394.    GIF_Send_Data(code);
  395.    old=code;
  396.    code=GIF_Get_Code(fp,fout);
  397.   }
  398.  } while(code!=EOI);
  399. }
  400.  
  401. void GIF_Get_Next_Entry(fp)
  402. FILE *fp;
  403. {
  404.    /* table walk to empty spot */
  405.  while(  (table[nextab].valid==1)
  406.        &&(nextab<MAXVAL)
  407.       ) nextab++;
  408.  /* 
  409.   * Ran out of space?!  Something's gone sour...
  410.   */
  411.  if (nextab>=MAXVAL)    
  412.  { 
  413.   fprintf(stderr,"Error: GetNext nextab=%d\n",nextab);
  414.   fclose(fp);
  415.   TheEnd();
  416.  }
  417.  if (nextab==INCSIZE)   /* go to next table size (and LZW code size ) */
  418.  {
  419.    /* fprintf(stderr,"GetNext INCSIZE was %d ",nextab); */
  420.    code_size++; INCSIZE=(INCSIZE*2)+1;
  421.    if (code_size>=12) code_size=12;
  422. /*   fprintf(stderr,"<%d>",INCSIZE); */
  423.  }
  424.  
  425. }
  426. /*  body is associated string
  427.     next is code to add to that string to form associated string for
  428.     index
  429. */     
  430.  
  431. void GIF_Add_To_Table(body,next,index)
  432. register ULONG body,next,index;
  433. {
  434.  if (index>MAXVAL)
  435.  { 
  436.   fprintf(stderr,"Error index=%d\n",index);
  437.  }
  438.  else
  439.  {
  440.   table[index].valid=1;
  441.   table[index].data=table[next].first;
  442.   table[index].first=table[body].first;
  443.   table[index].last=body;
  444.  }
  445. }
  446.  
  447. void GIF_Send_Data(index)
  448. register int index;
  449. {
  450.  register int i,j;
  451.  i=0;
  452.  do         /* table walk to retrieve string associated with index */
  453.  { 
  454.   gif_buff[i]=table[index].data; 
  455.   i++;
  456.   index=table[index].last;
  457.   if (i>MAXVAL)
  458.   { 
  459.    fprintf(stderr,"Error: Sending i=%d index=%d\n",i,index);
  460.    TheEnd();
  461.   }
  462.  } while(index>=0);
  463.  
  464.  /* now invert that string since we retreived it backwards */
  465.  i--;
  466.  for(j=i;j>=0;j--)
  467.  {
  468.   /*pic[pic_i] = gif_buff[j] | gif_pix_offset;*/
  469.   pic_i++;
  470.  }
  471. }
  472.  
  473.  
  474. /* 
  475.  * initialize string table 
  476.  */
  477. void GIF_Init_Table()       
  478. {
  479.  register int maxi,i;
  480.  
  481. if (debug_flag) fprintf(stderr,"Initing Table...");
  482.  maxi=gif_ptwo[root_code_size];
  483.  for(i=0; i<maxi; i++)
  484.  {
  485.   table[i].data=i;   
  486.   table[i].first=i;
  487.   table[i].valid=1;  
  488.   table[i].last = -1;
  489.  }
  490.  CLEAR=maxi; 
  491.  EOI=maxi+1; 
  492.  nextab=maxi+2;
  493.  INCSIZE = (2*maxi)-1;
  494.  code_size=root_code_size+1;
  495. }
  496.  
  497.  
  498. /* 
  499.  * clear table 
  500.  */
  501. void GIF_Clear_Table()   
  502. {
  503.  register int i;
  504. if (debug_flag) fprintf(stderr,"Clearing Table...\n");
  505.  for(i=0;i<MAXVAL;i++) table[i].valid=0;
  506.  GIF_Init_Table();
  507. }
  508.  
  509. /*CODE*/
  510. ULONG GIF_Get_Code(fp,fout) /* get code depending of current LZW code size */
  511. FILE *fp,*fout;
  512. {
  513.  ULONG code;
  514.  register int tmp;
  515.  
  516.  while(num_bits < code_size)
  517.  {
  518.   /**** if at end of a block, start new block */
  519.   if (gif_block_size==0) 
  520.   {
  521.    tmp = fgetc(fp);
  522.    if (tmp >= 0 )
  523.    {
  524.     fputc(tmp,fout);
  525.     gif_block_size=(ULONG)(tmp);
  526.    }
  527.    else TheEnd1("EOF in data stream\n");
  528.   }
  529.  
  530.   tmp = fgetc(fp);   gif_block_size--;
  531.   if (tmp >= 0)
  532.   {
  533.    fputc(tmp,fout);
  534.    bits |= ( ((ULONG)(tmp) & 0xff) << num_bits );
  535.    num_bits+=8;
  536.   }
  537.   else TheEnd1("EOF in data stream\n");
  538.  }
  539.   
  540.  code = bits & gif_mask[code_size];
  541.  bits >>= code_size;
  542.  num_bits -= code_size; 
  543.  
  544.  
  545.  if (code>MAXVAL)
  546.  { 
  547.   fprintf(stderr,"\nError! in stream=%x \n",code); 
  548.   fprintf(stderr,"CLEAR=%x INCSIZE=%x EOI=%x code_size=%x \n",
  549.                                            CLEAR,INCSIZE,EOI,code_size); 
  550.   code=EOI;
  551.  }
  552.  
  553.  if (code==INCSIZE)
  554.  {
  555.   if (code_size<12)
  556.   {
  557.    code_size++; INCSIZE=(INCSIZE*2)+1;
  558.   }
  559.   else if (debug_flag) fprintf(stderr,"<13?>"); 
  560.  }
  561.  
  562.  return(code);
  563. }
  564.  
  565.  
  566. /* 
  567.  * read GIF header 
  568.  */
  569. void GIF_Screen_Header(fp,fout,first_time)
  570. FILE *fp,*fout;
  571. int first_time;
  572. {
  573.  int temp,i;
  574.  
  575.  for(i=0;i<6;i++)
  576.  {
  577.   temp = fgetc(fp);
  578.   if(i==4 && temp == '7') temp='9';
  579.   if (first_time==TRUE) fputc(temp,fout);
  580.  }
  581.  
  582.  gifscrn.width  = GIF_Get_Short(fp,fout,first_time);
  583.  gifscrn.height = GIF_Get_Short(fp,fout,first_time);
  584.  temp=fgetc(fp);                 if (first_time==TRUE) fputc(temp,fout);
  585.  gifscrn.m       =  temp & 0x80;
  586.  gifscrn.cres    = (temp & 0x70) >> 4;
  587.  gifscrn.pixbits =  temp & 0x07;
  588.  
  589.  gifscrn.bc  = fgetc(fp);
  590.  if (first_time==TRUE) 
  591.     {
  592.     /* we really should set the background color to the transparent color */
  593.     fputc(gifscrn.bc,fout);
  594.     }
  595.  
  596.  temp=fgetc(fp);                 if (first_time==TRUE) fputc(temp,fout);
  597.  imagec=gif_ptwo[(1+gifscrn.pixbits)];
  598.  
  599.  if (verbose)
  600.   fprintf(stderr,"Screen: %dx%dx%d m=%d cres=%d bkgnd=%d pix=%d\n",
  601.     gifscrn.width,gifscrn.height,imagec,gifscrn.m,gifscrn.cres,
  602.     gifscrn.bc,gifscrn.pixbits);
  603.  
  604.  if(global.trans.type==TRANS_RGB) global.trans.valid=0;
  605.  if (gifscrn.m)
  606.  {
  607.   for(i=0;i<imagec;i++)
  608.   {
  609.    gif_cmap[i].cmap.red   = temp = fgetc(fp); 
  610.            if (first_time==TRUE) fputc(temp,fout);
  611.    gif_cmap[i].cmap.green = temp = fgetc(fp); 
  612.            if (first_time==TRUE) fputc(temp,fout);
  613.    gif_cmap[i].cmap.blue  = temp = fgetc(fp); 
  614.            if (first_time==TRUE) fputc(temp,fout);
  615.  
  616.    if(global.trans.type==TRANS_RGB && !global.trans.valid)
  617.     if(global.trans.red==gif_cmap[i].cmap.red &&
  618.     global.trans.green==gif_cmap[i].cmap.green &&
  619.     global.trans.blue==gif_cmap[i].cmap.blue) {
  620.       if(debug_flag>1) fprintf(stderr," Transparent match at %d\n",i);
  621.         global.trans.map=i;
  622.     global.trans.valid=TRUE;
  623.     }
  624.   }
  625.  }
  626.  screen_was_last = TRUE;
  627. }
  628.  
  629. void GIF_Image_Header(fp,fout,first_time)
  630. FILE *fp,*fout;
  631. int first_time;
  632. {
  633.  int temp,tnum,i,r,g,b;
  634.  
  635.  gifimage.left   = GIF_Get_Short(fp,fout,1);
  636.  if(global.left) gifimage.left+=global.left;
  637.  
  638.  gifimage.top    = GIF_Get_Short(fp,fout,1);
  639.  if(global.top) gifimage.top+=global.top;
  640.  
  641.  gifimage.width  = GIF_Get_Short(fp,fout,1);
  642.  gifimage.height = GIF_Get_Short(fp,fout,1);
  643.  temp=fgetc(fp); 
  644.  
  645.  
  646.     
  647.  gifimage.i        = temp & 0x40;
  648.  gifimage.pixbits  = temp & 0x07;
  649.  gifimage.m        = temp & 0x80;
  650.  
  651.  /* this sets the local colormap bit to true */
  652.  if (screen_was_last && (first_time==FALSE)) temp |= 0x80;
  653.  
  654.  temp &= 0xf8;
  655.  temp |= gifscrn.pixbits;
  656.  fputc(temp,fout);
  657.  
  658.  imagex=gifimage.width;
  659.  imagey=gifimage.height;
  660.  tnum=gif_ptwo[(1+gifimage.pixbits)];
  661.  if (verbose)
  662.   fprintf(stderr,"Image: %dx%dx%d (%d,%d) m=%d i=%d pix=%d \n",
  663.     imagex,imagey,tnum,gifimage.left,gifimage.top,
  664.     gifimage.m,gifimage.i,gifimage.pixbits);
  665.  
  666.  /* if there is an image cmap, then use it */
  667.  
  668.  if (gifimage.m)
  669.  {
  670.   if(debug_flag) fprintf(stderr,"DEBUG:Transferring colormap of %d colors\n",
  671.             imagec);
  672.   for(i=0;i<tnum;i++)
  673.   {
  674.    gif_cmap[i].cmap.red   = r = fgetc(fp);
  675.    gif_cmap[i].cmap.green = g = fgetc(fp);
  676.    gif_cmap[i].cmap.blue  = b = fgetc(fp);
  677.    fputc(r,fout);
  678.    fputc(g,fout);
  679.    fputc(b,fout);
  680.   }
  681.  }  /* else if screen was last not 1st time */
  682.  else if (screen_was_last && (first_time==FALSE))
  683.  {
  684.   if(debug_flag>1) fprintf(stderr,"DEBUG:Writing colormap of %d colors\n",
  685.             imagec);
  686.   for(i=0;i<imagec;i++)
  687.   {
  688.    fputc(gif_cmap[i].cmap.red  ,fout);
  689.    fputc(gif_cmap[i].cmap.green,fout);
  690.    fputc(gif_cmap[i].cmap.blue ,fout);
  691.   }
  692.  }
  693.  screen_was_last = FALSE; 
  694. }
  695.  
  696.  
  697. /*
  698.  *
  699.  */
  700. int GIF_Get_Short(fp,fout,first_time)
  701. FILE *fp,*fout;
  702. int first_time;
  703. {
  704.  register int temp,tmp1;
  705.  temp=fgetc(fp);     if (first_time==TRUE) fputc(temp,fout);
  706.  tmp1=fgetc(fp);     if (first_time==TRUE) fputc(tmp1,fout);
  707.  return(temp|( (tmp1) << 8 ));
  708. }
  709.  
  710. void GIF_Comment(fout,string)
  711. FILE *fout;
  712. char *string;
  713. {
  714. if(!string || !strlen(string))
  715.         {
  716.         /* Bogus string */
  717.         if(debug_flag) fprintf(stderr,"GIF_Comment: invalid argument");
  718.         return;
  719.         }
  720. fputc(0x21,fout);
  721. fputc(0xFE,fout);
  722. fputs(string,fout);
  723. fputc(0,fout);
  724. }
  725.  
  726. /*
  727.  * Write a Netscape loop marker.
  728.  */
  729. void GIF_Loop(fout,repeats)
  730. FILE *fout;
  731. unsigned int repeats;
  732. {
  733. UBYTE low=0,high=0;
  734. if(repeats) {
  735.     /* non-zero repeat count- Netscape hasn't implemented this yet */
  736.     high=repeats / 256;
  737.     low=repeats % 256;
  738.     }
  739.  
  740. fputc(0x21,fout);
  741. fputc(0xFF,fout);
  742. fputc(0x0B,fout);
  743. fputs("NETSCAPE2.0",fout);
  744. fputc(0x03,fout);
  745. fputc(0x01,fout);
  746.  
  747. fputc(low,fout); /* the delay count - 0 for infinite */
  748. fputc(high,fout); /* second byte of delay count */
  749. fputc(0x00,fout); /* terminator */
  750.  
  751. if(verbose) fprintf(stderr,"Wrote loop extension\n");
  752. }
  753.  
  754. /*
  755.  * GIF_GCL - add a Control Label to set an inter-frame delay value.
  756.  */
  757. void GIF_GCL(fout,delay)
  758. FILE * fout;
  759. unsigned int delay;
  760. {
  761. UBYTE low=0,high=0,flag;
  762. if(delay) {
  763.     /* non-zero delay, figure out low/high bytes */
  764.     high=delay / 256;
  765.     low=delay % 256;
  766.     }
  767.  
  768. fputc(0x21,fout);
  769. fputc(0xF9,fout);
  770. fputc(0x04,fout);
  771.  
  772. flag = global.disposal <<2;
  773. if(delay) flag |=0x80;
  774. if(global.trans.valid) flag |=0x01;
  775. fputc(flag,fout);
  776.  
  777. fputc(low,fout); /* the delay speed - 0 is instantaneous */
  778. fputc(high,fout); /* second byte of delay count */
  779.  
  780. fputc(global.trans.map,fout);
  781. fputc(0,fout);
  782. if(debug_flag>1) {
  783.   fprintf(stderr,"GCL: delay %d",delay);
  784.   if(global.trans.valid) fprintf(stderr," Transparent: %d",global.trans.map);
  785.   fputc('\n',stderr);
  786.   }
  787. }
  788.  
  789.  
  790. void Calc_Trans(string)
  791. char * string;
  792. {
  793. if(string[0] != '#') {
  794.   global.trans.type=TRANS_MAP;
  795.   global.trans.map=atoi(string);
  796.   global.trans.valid=1;
  797.   }
  798. else
  799.   {
  800.   /* it's an RGB value */
  801.   int r,g,b;
  802.   string++;
  803.   if(3==sscanf(string,"%2x%2x%2x",&r,&g,&b)) {
  804.     global.trans.red=r;
  805.     global.trans.green=g;
  806.     global.trans.blue=b;
  807.     global.trans.type=TRANS_RGB;
  808.     if(debug_flag) fprintf(stderr,"Transparent RGB=(%x,%x,%x)\n",r,g,b);
  809.     }
  810.   }
  811. if(debug_flag) fprintf(stderr,"DEBUG:Calc_trans is %d\n",global.trans.type);
  812. }
  813.  
  814. void set_offset(string)
  815. char * string;
  816. {
  817. char *off_x,*off_y;
  818. off_x=(char *) strtok(string,",");
  819. off_y=(char *)strtok((char *)NULL,",");
  820. if(off_x && off_y) {
  821.     /* set the offset */
  822.     global.left=atoi(off_x);
  823.     global.top=atoi(off_y);
  824.     if(debug_flag>1) fprintf(stderr,"Offset changed to %d,%d\n",
  825.         global.left,global.top);
  826.     return;
  827.     }
  828. if(debug_flag>1) fprintf(stderr,"Couldn't parse offset values.\n");
  829. exit(1);
  830. }
  831.